package com.gitee.chessboard.scan.discern;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;

import java.util.List;

import static org.objectweb.asm.Opcodes.*;

/**
 * 注解识别器
 *
 * @author 敲代码的旺财
 * @date 2021/12/10 16:42
 */
public class AnnotationDiscernPortion extends AbstractDiscernPortion {
    private String name;

    @Override
    public boolean discern(ClassReader cr) {
        if (!(targetDescribe instanceof Class)) {
            throw new RuntimeException(targetDescribe + "不是一个Class对象");
        }
        Class<?> clazz = (Class<?>) targetDescribe;
        if (!clazz.isAnnotation()) {
            throw new RuntimeException(clazz + "不是一个注解的Class对象");
        }
        this.name = clazz.getSimpleName();
        ClassNode cn = new ClassNode();
        cr.accept(cn, 0);
        //获取声明的所有注解
        List<AnnotationNode> annotations = cn.visibleAnnotations;
        if (annotations != null) {//便利注解
            for (AnnotationNode an : annotations) {
                //获取注解的描述信息
                String anno = an.desc.replaceAll("/", ".");
                String annoName = anno.substring(1, anno.length() - 1);
                if (clazz.getName().equals(annoName)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public ClassVisitor beforeLoadHandle(ClassWriter cw) {
        return new NonClassVisitor(cw);
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getType() {
        return "annotation";
    }

    class NonClassVisitor extends ClassVisitor {
        public NonClassVisitor(ClassVisitor cv) {
            super(ASM9, cv);
        }

        @Override
        public void visit(int version, int access, String name, String
                signature, String superName, String[] interfaces) {
            //修改类的定义，将版本改成1.5
            cv.visit(V11, access, name, signature, superName, interfaces);
        }

    }
}
